package com.wenx;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.CharsetUtil;

import java.util.Date;

public class MyWebSocketHandler extends SimpleChannelInboundHandler<Object> {

    private WebSocketServerHandshaker handshaker;

    private static final String WEB_SOCKET_URL = "ws://localhost:8888/websocket";

    /**
     * 得到客户端连接触发
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        NettyConfig.channels.add(ctx.channel());
        System.out.println("客户端与服务器连接开启...");
    }

    /**
     * 关闭客户端连接触发
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        NettyConfig.channels.remove(ctx.channel());
        System.out.println("客户端与服务器连接关闭...");
    }

    /**
     * 获取数据
     * @param channelHandlerContext
     * @param o
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {
        if(o instanceof FullHttpRequest) {
            //处理客户端向服务器端发布http握手请求的业务
            handHttpRequest(channelHandlerContext,(FullHttpRequest) o);
        } else if(o instanceof WebSocketFrame) {
            //处理websocket连接业务
            handWebSocketFrame(channelHandlerContext,(WebSocketFrame) o);
        }
    }

    /**
     * 处理客户端向服务器发送websocket请求的业务
     * @param channelHandlerContext
     * @param webSocketFrame
     */
    private void handWebSocketFrame(ChannelHandlerContext channelHandlerContext, WebSocketFrame webSocketFrame) {
        //关闭websocket指令
        if (webSocketFrame instanceof CloseWebSocketFrame) {
            handshaker.close(channelHandlerContext.channel(),((CloseWebSocketFrame) webSocketFrame).retain());
        }
        //是否是ping消息
        if (webSocketFrame instanceof PingWebSocketFrame) {
            channelHandlerContext.channel().writeAndFlush(new PingWebSocketFrame(webSocketFrame.content().retain()));
            return;
        }
        //是否是二进制消息，如果是二进制消息，抛出异常
        if (!(webSocketFrame instanceof TextWebSocketFrame)) {
            System.out.println("不支持二进制消息");
            throw new RuntimeException("【"+this.getClass().getName()+"】不支持二进制消息");
        }
        //返回应答消息
        //获取服务端向客户端发送的消息
        String text = ((TextWebSocketFrame) webSocketFrame).text();
        System.out.println("服务端收到的消息 = " + text);

        TextWebSocketFrame textWebSocketFrame =
                new TextWebSocketFrame(new Date().toString() + channelHandlerContext.channel().id() + "===>>" + text);
        //群发消息，向每个注册的客户端发送消息
        NettyConfig.channels.writeAndFlush(textWebSocketFrame);
    }

    /**
     * 处理客户端向服务器端发布http握手请求的业务
     * @param ctx
     * @param req
     */
    private void handHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
        if(!req.decoderResult().isSuccess() || !("websocket".equals(req.headers().get("Upgrade")))) {
            sendHttpResponse(ctx,req,new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
            return;
        }

        WebSocketServerHandshakerFactory handshakerFactory =
                new WebSocketServerHandshakerFactory(WEB_SOCKET_URL,null,false);
        handshaker = handshakerFactory.newHandshaker(req);
        if(handshaker == null) {
            WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
        } {
            handshaker.handshake(ctx.channel(),req);
        }
    }

    /**
     * 服务端向客户端相应信息
     * @param ctx
     * @param req
     * @param res
     */
    private void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, DefaultFullHttpResponse res) {
        if(res.status().code() != 200) {
            ByteBuf byteBuf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8);
            res.content().writeBytes(byteBuf);
            res.release();
        }
        //服务端向客户端发送数据
        ChannelFuture future = ctx.channel().writeAndFlush(res);
        if(res.status().code() != 200) {
            future.addListener(ChannelFutureListener.CLOSE);
        }
    }

    /**
     * 读取数据完毕触发
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    /**
     * 出现异常触发
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}
